package com.zenithmind.gateway.security;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import jakarta.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * 默认安全策略处理器实现
 * 专门负责安全策略的业务逻辑处理
 * 遵循单一职责原则：只负责安全策略的判断和处理
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class DefaultSecurityPolicyHandler implements SecurityPolicyHandler {
    
    private final SecurityProperties securityProperties;
    
    /**
     * 路径匹配器，支持通配符匹配
     */
    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    @PostConstruct
    public void init() {
        log.info("安全策略处理器初始化完成");
        log.info("公开访问路径数量: {}", 
            securityProperties.getPublicPaths().size() + SecurityProperties.DEFAULT_PUBLIC_PATHS.size());
        log.info("受保护路径数量: {}", securityProperties.getProtectedPaths().size());
        
        if (log.isDebugEnabled()) {
            log.debug("默认公开访问路径列表: {}", SecurityProperties.DEFAULT_PUBLIC_PATHS);
            log.debug("配置的公开访问路径列表: {}", securityProperties.getPublicPaths());
            log.debug("受保护路径列表: {}", securityProperties.getProtectedPaths());
            log.debug("忽略URL列表: {}", getIgnoreUrlList());
        }
    }
    
    @Override
    public boolean shouldSkipAuth(String path) {
        log.trace("检查路径是否需要跳过权限校验: {}", path);

        // 检查默认公开路径列表
        for (String publicPath : SecurityProperties.DEFAULT_PUBLIC_PATHS) {
            if (publicPath.endsWith("/**")) {
                String prefix = publicPath.substring(0, publicPath.length() - 3);
                if (path.startsWith(prefix)) {
                    log.debug("路径 {} 匹配默认公开路径 {}, 跳过认证。", path, publicPath);
                    return true;
                }
            } else if (path.equals(publicPath)) {
                log.debug("路径 {} 在默认公开路径列表中，跳过认证。", path);
                return true;
            }
        }

        // 检查配置的公开路径列表
        for (String publicPath : securityProperties.getPublicPaths()) {
            if (pathMatcher.match(publicPath, path)) {
                log.debug("路径 {} 匹配公开访问模式 {}, 不需要认证", path, publicPath);
                return true;
            }
        }

        // 检查是否在受保护路径中
        for (String protectedPath : securityProperties.getProtectedPaths()) {
            if (pathMatcher.match(protectedPath, path)) {
                log.debug("路径 {} 匹配受保护模式 {}, 需要认证", path, protectedPath);
                return false;
            }
        }
        
        // 检查忽略的URL列表
        for (String ignoreUrl : getIgnoreUrlList()) {
            if (pathMatcher.match(ignoreUrl, path)) {
                log.debug("路径 {} 在忽略URL列表中，跳过认证", path);
                return true;
            }
        }

        // 默认策略：如果没有明确配置，则需要认证
        log.debug("路径 {} 未匹配任何规则，默认需要认证", path);
        return false;
    }

    @Override
    public boolean needAuthentication(String path) {
        return !shouldSkipAuth(path);
    }

    @Override
    public void addPublicPath(String path) {
        if (!securityProperties.getPublicPaths().contains(path)) {
            securityProperties.getPublicPaths().add(path);
            log.info("添加公开访问路径: {}", path);
        }
    }

    @Override
    public void addProtectedPath(String path) {
        if (!securityProperties.getProtectedPaths().contains(path)) {
            securityProperties.getProtectedPaths().add(path);
            log.info("添加受保护路径: {}", path);
        }
    }

    @Override
    public void removePublicPath(String path) {
        if (securityProperties.getPublicPaths().remove(path)) {
            log.info("移除公开访问路径: {}", path);
        }
    }

    @Override
    public void removeProtectedPath(String path) {
        if (securityProperties.getProtectedPaths().remove(path)) {
            log.info("移除受保护路径: {}", path);
        }
    }
    
    @Override
    public List<String> getIgnoreUrlList() {
        List<String> result = new ArrayList<>();
        String ignoreUrls = securityProperties.getIgnoreUrls();
        if (ignoreUrls != null && !ignoreUrls.isEmpty()) {
            String[] urls = ignoreUrls.split(",");
            for (String url : urls) {
                if (url != null && !url.trim().isEmpty()) {
                    result.add(url.trim());
                }
            }
        }
        return result;
    }
}
